package dp;

/**
 * @Description 剑指 Offer 47. 礼物的最大价值
 * @Author Firenut
 * @Date 2023-01-10 23:39
 */
public class T47_maxValue {
    // 法1
    // 定义: dp[i][j]表示到达该位置得到的最大价值
    // 递推关系: dp[i][j] = max(dp[i-1][j],dp[i][j-1])+grid[i][j]
    // 初始值: dp[0][0]=grid[0][0] dp[0][j]= grid[0][j]+grid[0][j-1]+...+grid[0][0], dp[i][0]=grid[i][0]+grid[i-1][0]+...+grid[0][0]
    // 返回值: dp[m-1][n-1]
    public int maxValue1(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int dp[][] = new int[m][n];
        dp[0][0] = grid[0][0];

        // 初始化dp数组的第一行
        for (int i = 1; i < n; i++) {
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        }

        // 初始化dp数组的第一列
        for (int i = 1; i < m; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }

        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }

        return dp[m - 1][n - 1];
    }


    // 法2 递归
    public int maxValue(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int memo[][] = new int[m][n];
        return dfs(0, 0, m, n, memo, grid);
    }

    //dfs
    int dfs(int x, int y, int m, int n, int memo[][], int[][] grid) {
        //越界(因为是向右和向下移动，所以不会出现x<0||y<0的情况)
        if (x >= m || y >= n) {
            return 0;
        }

        //到达终点
        if (x == m - 1 && y == n - 1) {
            return grid[x][y];
        }

        //如果存在重复解,直接返回即可
        if (memo[x][y] != 0) {
            return memo[x][y];
        }

        //向右移动
        int right = dfs(x + 1, y, m, n, memo, grid);

        //向下移动
        int down = dfs(x, y + 1, m, n, memo, grid);

        //从(x,y)出发,取 向下和向右走得到的价值的较大值 + 当前位置的价值
        memo[x][y] = Math.max(right, down) + grid[x][y];
        return memo[x][y];
    }


}
